package com.bootx.predict;

import com.bootx.predict.pojo.PredictPlugin;
import com.bootx.predict.pojo.PredictionResult;
import com.bootx.predict.pojo.RedPacketBatch;
import com.bootx.predict.pojo.RedPacketRecord;
import com.bootx.predict.util.PredictUtils;
import org.springframework.stereotype.Component;

import java.util.*;

@Component("logisticRegressionPredict")
public class LogisticRegressionPredict extends PredictPlugin {
    /**
     * windowSize：窗口大小，表示考虑最近多少个抢包记录作为特征（推荐 5~10）
     */
    private final int windowSize = 5;
    /**
     * weights：模型参数，根据训练数据计算得到
     */
    private final Double[] weights=new Double[]{
            -0.2, 0.6,0.4,0.2,0.1,0.05
    };

    @Override
    public String getName() {
        return "logisticRegressionPredict";
    }

    @Override
    public List<PredictionResult> predict(List<RedPacketBatch> list, Set<Integer> indexes) {
        List<RedPacketRecord> history = PredictUtils.parseData(list);
        Map<Integer, List<Boolean>> grouped = new HashMap<>();
        Map<Integer, List<Integer>> timeMap = new HashMap<>();

        for (RedPacketRecord r : history) {
            grouped.computeIfAbsent(r.getIndex(), k -> new ArrayList<>())
                    .add(PredictUtils.isAmountOdd(r.getAmount()));
            timeMap.computeIfAbsent(r.getIndex(), k -> new ArrayList<>())
                    .add(r.getOpenTime());
        }

        List<PredictionResult> results = new ArrayList<>();
        for (int idx : indexes) {
            List<Boolean> states = grouped.getOrDefault(idx, Collections.emptyList());
            int total = states.size();
            int oddCount = (int) states.stream().filter(b -> b).count();
            double avgOpenTime = timeMap.getOrDefault(idx, Collections.emptyList())
                    .stream().mapToInt(Integer::intValue).average().orElse(0);

            double probability = 0.5;
            if (states.size() >= windowSize) {
                probability = predictProbability(states, weights);
            }

            results.add(new PredictionResult(idx, total, oddCount, probability, Double.valueOf(avgOpenTime+"").intValue()));
        }
        return results;
    }
    private double predictProbability(List<Boolean> states, Double[] weights) {
        int len = weights.length - 1;
        double z = weights[0];
        for (int i = 0; i < len; i++) {
            // 取最近 windowSize 个状态，0/1 转换
            boolean state = states.get(states.size() - 1 - i);
            z += weights[i + 1] * (state ? 1 : 0);
        }
        return sigmoid(z);
    }

    private double sigmoid(double z) {
        return 1.0 / (1.0 + Math.exp(-z));
    }
}
